#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/AST.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/CodeGen/CodeGenAction.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/TargetSelect.h"

using namespace clang;
using namespace llvm;

class MyASTConsumer : public ASTConsumer {
public:
  virtual bool HandleTopLevelDecl(DeclGroupRef DG) override {
    for (auto D : DG) {
      if (auto FD = dyn_cast<FunctionDecl>(D)) {
        FD->dump();
      }
    }
    return true;
  }
};

class MyFrontendAction : public ASTFrontendAction {
public:
  virtual std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, StringRef file) override {
    return std::make_unique<MyASTConsumer>();
  }
};

int main(int argc, const char **argv) {
  InitializeNativeTarget();
  InitializeNativeTargetAsmPrinter();

  CompilerInstance CI;
  CI.createDiagnostics();

  std::shared_ptr<clang::TargetOptions> TO = std::make_shared<clang::TargetOptions>();
  TO->Triple = llvm::sys::getDefaultTargetTriple();
  TargetInfo *TI = TargetInfo::CreateTargetInfo(CI.getDiagnostics(), TO);
  CI.setTarget(TI);

  CI.createFileManager();
  CI.createSourceManager(CI.getFileManager());
  CI.createPreprocessor(clang::TU_Module);
  CI.createASTContext();

  std::vector<const char *> Args(argv + 1, argv + argc);
  clang::CompilerInvocation::CreateFromArgs(CI.getInvocation(), Args, CI.getDiagnostics());
  CI.createASTContext();

  MyFrontendAction action;
  if (!CI.ExecuteAction(action)) {
    return 1;
  }

  return 0;
}
